package top.java.collectionTest;


import org.junit.Test;

import java.util.HashMap;
import java.util.Hashtable;

/**
 *    Map接口 ：双列数据       用来存储一对(Key - Value)一对的对象    (jdk1.2出现的)
 *
 *           -HashMap：作为 Map 的主要实现类，跟随着 Map jdk1.2时出现，线程不安全，效率高，
 *                     可以存储null的key和value
 *              -LinkedHashMap：jdk1.4 出现。在原有的HashMap的基础上加了一对指针指向前一个数据和后一个数据
 *                              可以按照添加的顺序实现遍历，对于频繁的遍历操作，此类效率高于HashMap
 *           -TreeMap：跟随着 Map jdk1.2时出现，保证按照添加的key-value键值对进行排序，实现排序遍历，
 *                     通过key排序，重写自然或者定制排序考虑key，底层使用红黑树
 *           -HashTable：作为古老的实现类，jdk 1.0 就有，线程安全，效率低，不可以存储null的key和value
 *              -Properties：HashTable的子类，常用来处理配置文件，key和value都是String类型
 *
 *     HashMap的底层：数组 + 链表   (jdk 7及以前)
 *                  数组 + 链表 + 红黑树   (jdk 8)
 *
 *     面试题：
 *     1.HashMap的底层实现原理？
 *     2.HashMap 和 HashTable 的异同？
 *     3.CurrentHashMap 与 HashTable 的异同？（暂时不讲）
 *
 *    HashMap在jdk7中实现原理：
 *     HashMap map = new HashMap():
 *     在实例化以后，底层创建了长度是16的一维数组Entry[] table。
 *     ...可能已经执行过多次put...
 *     map.put(key1,value1):
 *     首先，调用key1所在类的hashCode()计算key1哈希值，此哈希值经过某种算法计算以后，得到在Entry数组中的存放位置。
 *
 *          如果此位置上的数据为空，此时的key1-value1添加成功。 ----情况1
 *          如果此位置上的数据不为空，(则此位置上存在一个或多个数据(以链表形式存在)),比较key1和其他数据的哈希值：
 *
 *               如果key1的哈希值与已经存在的数据的哈希值都不相同，此时key1-value1添加成功。----情况2
 *
 *               如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同，继续比较：
 *               调用key1所在类的equals(key2)方法，比较：
 *
 *                       如果equals()返回false:此时key1-value1添加成功。----情况3
 *                       如果equals()返回true:使用value1替换value2。
 *
 *       补充：关于情况2和情况3：此时key1-value1和原来的数据以链表的方式存储。
 *
 *       在不断的添加过程中，会涉及到扩容问题，当超出临界值(且要存放的位置非空)时，扩容。
 *       默认的扩容方式：扩容为原来容量的2倍，并将原的数据复制过来。
 *
 *       HashMap在jdk8中相较于jdk7在底层实现方面的不同：
 *       new HashMap():底层没创建一个长度为16的数组
 *       jdk 8底层的数组是：Node[],而非Entry[]
 *       首次调用put()方法时，底层创建长度为16的数组
 *       jdk7底层结构只：数组+链表。jdk8中底层结构：数组+链表+红黑树。
 *       形成链表时，七上八下（jdk7:新的元素指向旧的元素。jdk8：旧的元素指向新的元素）
 *       当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时，
 *       此时此索引位置上的所数据改为使用红黑树存储。
 *
 *      HashMap底层典型属性的属性的说明：
 *      DEFAULT_INITIAL_CAPACITY : HashMap的默认容量，16
 *      DEFAULT_LOAD_FACTOR：HashMap的默认加载因子：0.75
 *      threshold：扩容的临界值，=容量*填充因子：16 * 0.75 => 12
 *      TREEIFY_THRESHOLD：Bucket中链表长度大于该默认值，转化为红黑树:8
 *      MIN_TREEIFY_CAPACITY：桶中的Node被树化时最小的hash表容量:64
 *
 */
public class MapTest1 {

    @Test
    public void test1() {
        HashMap hashMap = new HashMap();
        hashMap.put(null,123);
        hashMap.put(null,null);

        //Hashtable中存储null报NullPointerException
        Hashtable hashtable = new Hashtable();
     //   hashtable.put(null,123);                    // NullPointerException

    }


    @Test
    public void test2() {


    }
}
